import javax.swing.JTextArea;


public class IntelligentPlayer extends Player {
	
	public IntelligentPlayer(int size, String name, JTextArea textArea) {
		super(size, name, textArea);
/*		biggerBoard = new Board(gameSize + 2);
		for (int i = 0; i < gameSize + 2; i++) {
			biggerBoard.setField(0, i, Board.TRIED);
			biggerBoard.setField(i, 0, Board.TRIED);
			biggerBoard.setField(i, gameSize + 1, Board.TRIED);
			biggerBoard.setField(gameSize + 1, i, Board.TRIED);
		}*/
	}
	
	protected void fillEmpty(int x, int y) {
		int orgX = x;
		int orgY = y;
		//N
		while (isMySinking(x, y)) {
			fillEmptyAround(x, y);
			y--;
		}
		x = orgX;
		y = orgY;
		//E
		while (isMySinking(x, y)) {
			fillEmptyAround(x, y);
			x++;
		}
		x = orgX;
		y = orgY;
		//S
		while (isMySinking(x, y)) {
			fillEmptyAround(x, y);
			y++;
		}
		x = orgX;
		y = orgY;
		//W
		while (isMySinking(x, y)) {
			fillEmptyAround(x, y);
			x--;
		}
	}
	
	protected int partOfShip(int x, int y) {
		int count = 1;
		//N
		while (isOpShip(x, --y)) {
			count++;
			y--;
		}
		//E
		while (isOpShip(++x, y)) {
			count++;
			x++;
		}
		//S
		while (isOpShip(x, ++y)) {
			count++;
			y++;
		}
		//W
		while (isOpShip(--x, y)) {
			count++;
			x--;
		}
		//return count;
		//error in x, y
		return 0;
	}
	
	private void fillEmptyAround(int x, int y) {
		//N
		if (isOpFree(x, y - 1)) {
			setTried(x, y - 1);
		}
		//NE
		if (isOpFree(x + 1, y - 1)) {
			setTried(x + 1, y - 1);
		}
		//E
		if (isOpFree(x + 1, y)) {
			setTried(x + 1, y);
		}
		//SE
		if (isOpFree(x + 1, y + 1)) {
			setTried(x + 1, y + 1);
		}
		//S
		if (isOpFree(x, y + 1)) {
			setTried(x, y + 1);
		}
		//SW
		if (isOpFree(x - 1, y + 1)) {
			setTried(x - 1, y + 1);
		}
		//W
		if (isOpFree(x - 1, y)) {
			setTried(x - 1, y);
		}
		//NW
		if (isOpFree(x - 1, y - 1)) {
			setTried(x - 1, y - 1);
		}
	}
	
	private boolean isOpFree(int x, int y) {
		if (opBoard.getField(x, y) == Board.FREE) {
			return true;
		}
		return false;
	}
	
	private boolean isOpShip(int x, int y) {
		if (opBoard.getField(x, y) == Board.STROKE)
			return true;
		return false;
	}
	
	private boolean isOpEmpty(int x, int y) {
		if (opBoard.getField(x, y) == Board.FREE)
			return true;
		return false;
	}	
	 
	private void setTried(int x, int y) {
		opBoard.setField(x, y, Board.TRIED);
	}
	
	private int findEmptyNearStroke() {
		for (int x = 1; x <= gameSize; x++) {
			for (int y = 1; y <= gameSize; y++) {
				if (isOpStroke(x, y)) {
					int empty = findEmptyAround(x, y);
					if (empty >= 0) {
						return empty;
					}
				}
			}
		}
		return -1;
	}
	
	private int findEmptyContinuityNearStroke() {		
		for (int x = 1; x <= gameSize; x++) {
			for (int y = 1; y <= gameSize; y++) {
				if (isOpStroke(x, y)) {
					int empty = findEmptyContinuity(x, y);
					if (empty >= 0) {
						return empty;
					}
				}
			}
		}
		return -1;
	}
	
	private int findEmptySimply() {
		int x;
		int y;
		while (true) {
			//Randomly search for empty
			x = r.nextInt(gameSize) + 1;
			y = r.nextInt(gameSize) + 1;
			if (opBoard.getField(x, y) != Board.FREE) {
				//tried - once again
			} else {
				//haven't tried
				return ((y) - 1) * gameSize + (x) - 1;
			}
		}
	}
	
	private int findEmptyAround(int x, int y) {
		if (isOpEmpty(x - 1, y))
			return ((y) - 1) * gameSize + (x - 1) - 1;

		if (isOpEmpty(x, y - 1))
			return ((y - 1) - 1) * gameSize + (x) - 1;

		if (isOpEmpty(x, y + 1))
			return ((y + 1) - 1) * gameSize + (x) - 1;

		if (isOpEmpty(x + 1, y))
			return ((y) - 1) * gameSize + (x + 1) - 1;
		return -1;
	}
	
	private int findEmptyContinuity(int x, int y) {
		if (isOpEmpty(x - 1, y) && isOpStroke(x + 1, y))
			return ((y) - 1) * gameSize + (x - 1) - 1;

		if (isOpEmpty(x, y - 1) && isOpStroke(x, y + 1))
			return ((y - 1) - 1) * gameSize + (x) - 1;

		if (isOpEmpty(x, y + 1) && isOpStroke(x, y - 1))
			return ((y + 1) - 1) * gameSize + (x) - 1;

		if (isOpEmpty(x + 1, y) && isOpStroke(x - 1, y))
			return ((y) - 1) * gameSize + (x + 1) - 1;
		return -1;
	}
	
	/*
	 * (non-Javadoc)
	 * @see Player#strike()
	 */
	@Override
	public int strike() {
		boolean searching = true;
		int x = 0;
		int y = 0;
		int empty = 0;
		//Find ship with continuity
		if (searching) {
			empty = findEmptyContinuityNearStroke();
			if (empty >=0) {
				searching = false;
				x = empty % gameSize + 1;
				y = empty / gameSize + 1;
			}		
		}
		
		//Find and ship
		if (searching) {
			empty = findEmptyNearStroke();
			if (empty >=0) {
				searching = false;
				x = empty % gameSize + 1;
				y = empty / gameSize + 1;
			}
		}

		//Randomly search for empty
		//Find an empty field
		if (searching) {
			empty = findEmptySimply();
			if (empty >=0) {
				searching = false;
				x = empty % gameSize + 1;
				y = empty / gameSize + 1;
			}
		}
		
		int answer = opponent.ask(x, y);
		if (answer == Player.HIT) {
			//successful stroke
			opBoard.setField(x, y, Board.STROKE);
			allShipsFields--;
			if (allShipsFields > 0) {
				//still are opponents ships
				return Player.HIT;
			} else {
				//won
				return Player.WON;
			}
		} else if (answer == Player.SUNK) {
			//successful stroke - sunk
			opBoard.setField(x, y, Board.STROKE);
			setOpSunk(x, y);
			fillEmpty(x, y);
			allShipsFields--;
			if (allShipsFields > 0) {
				//still are opponents ships
				return Player.HIT;
			} else {
				//won
				return Player.WON;
			}
		} else {
			//unsuccessful stroke
			opBoard.setField(x, y, Board.TRIED);
			return Player.EMPTY;					
		}		
	}
	
}
